package com.linran.utils.jackson;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author lin
 * @date 2020-08-10 18:10
 */
@Setter
@Getter
public class CommonBeanResponse<T> {

    private T data;

    @JsonProperty("request_id")
    private String requestId;

    @JsonProperty("server_time")
    private long serverTime;

    @JsonProperty("result_code")
    private String resultCode;

    @JsonProperty("vehicle_user_role")
    private VehicleUserRole vehicleUserRole;


    private String jsonValue = "asdflinxcfasf";

    private String message;

    //@JsonValue
    public String getJsonValue() {
        return jsonValue;
    }

    public static void main(String[] args) throws IOException {
        // 1.TypeReference序列化
        CommonBeanResponse<UserBean> responseSrc = new CommonBeanResponse<>();
        responseSrc.setRequestId("sicuwf1s89f");
        responseSrc.setServerTime(123456L);
        responseSrc.setResultCode("succ");
        responseSrc.setMessage("请求成功");
        UserBean userBean = new UserBean();
        userBean.setName("lin");
        userBean.setHeight(175L);
        responseSrc.setData(userBean);

        ObjectMapper objectMapper = new ObjectMapper();

        //"{\"data\":{\"name\":\"lin\",\"height\":175},\"message\":\"请求成功\",\"request_id\":\"sicuwf1s89f\",\"server_time\":123456,\"result_code\":\"succ\"}"
        String jsonStr = objectMapper.writeValueAsString(responseSrc);
        System.out.println(jsonStr);

        // 虽然以下两个方法都能正常反序列化，但是还是有一些细微差别
        // 正确，可序列化为具体的UserBean 泛型方法readValue传递了CommonBeanResponse<UserBean>中的参数UserBean,最终成为 UserBean readValue(..);
        CommonBeanResponse<UserBean> responseDst = objectMapper.readValue(jsonStr, new TypeReference<CommonBeanResponse<UserBean>>() {
        });

        // 错误, 反序列化后data域是一堆k-v map(LinkedHashMap)
        CommonBeanResponse commonBeanResponse = objectMapper.readValue(jsonStr, CommonBeanResponse.class);

        //2.list
        List<UserBean> beanList = List.of(new UserBean("zhangsan", 172L), new UserBean("wangwu", 175L));
        String jsontList = objectMapper.writeValueAsString(beanList);
        List<UserBean> userBeanList = objectMapper.readValue(jsontList, new TypeReference<List<UserBean>>() {
        });
        //3.Map<String,Object>
        Map<String, Object> map = objectMapper.readValue(jsonStr, new TypeReference<Map<String, Object>>() {
        });
    }
}

@Setter
@Getter
@AllArgsConstructor
class UserBean {
    public UserBean() {
    }

    private String name;
    private Long height;
}

@Getter
enum VehicleUserRole {
    /**
     * 枚举类
     */
    UNKNOWN((byte) 0, "未知"),
    VehicleUserRole1((byte) 1, "1"),
    VehicleUserRole2((byte) 2, "2"),
    VehicleUserRole3((byte) 3, "3");

    private byte code;
    private String name;

    VehicleUserRole(byte code, String name) {
        this.code = code;
        this.name = name;
    }

    public static final Map<Byte, VehicleUserRole> map;

    static {
        map = Collections.unmodifiableMap(Stream.of(VehicleUserRole.values()).collect(Collectors.toMap(VehicleUserRole::getCode, UnaryOperator.identity())));
    }

//    @JsonCreator
//    public static VehicleUserRole getVehicleUserRole(String str) {
//        if (StringUtils.isBlank(str)) {
//            return UNKNOWN;
//        }
//        //有IllegalArgumentException风险
//        return VehicleUserRole.valueOf(str.trim().toUpperCase());
//    }

    @JsonCreator
    public static VehicleUserRole forValue(String nameString){
        for (VehicleUserRole operatorRole : values()) {
            if (operatorRole.toString().equalsIgnoreCase(nameString)){
                return operatorRole;
            }
        }
        return UNKNOWN;
    }

    public static VehicleUserRole get(byte code){
        return map.get(code);
    }
}